/*-
 * Copyright (c) 2009-2010 David Forsythe.
 * See LICENSE file for license details.
 */

#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/tree.h>
#include <sys/types.h>

#include "database.h"
/* Cool kids club. */
#include "internal.h"

#include "util.h"

#define MAGIC   0x00000001

struct pkg_database *
pkg_database_create(void)
{
        struct pkg_database *db;

        db = calloc(1, sizeof(*db));
        if (db == NULL) {
                return (NULL);
        }

        db->magic = MAGIC;
        db->internal = NULL;
        db->vtable = NULL;
        db->status = CLOSED;

        return (db);
}

/* 
 * Verify the magic value in a package database.  If there is a mismatch, crash
 * the client application.
 */
void
_pkg_database_check_magic(struct pkg_database *db, const char *func)
{
        if (db->magic != MAGIC) {
                PKG_CLIENT_CRASH(func, "database magic number mismatch.");
        }
}

/* Release a package database from memory. */
void
pkg_database_release(struct pkg_database *db)
{
        _pkg_database_check_magic(db, __func__);

        if (db->status != CLOSED) {
                warnx("closing pkg_database before free()");
                db->vtable->close(db);
        }

        free(db);
}

void
_pkg_database_set_vtable(struct pkg_database *db, struct pkg_database_vtable *vt)
{
        db->vtable = vt;
}

/* 
 * Do a check on the magic value, attributes, and vtable of a database, then
 * call its open callback.
 */
int
pkg_database_open(struct pkg_database *db, const char *location, u_int f)
{
        int r;

        _pkg_database_check_magic(db, __func__);

#if 0
        debug_logger(LOG_LIBRARY, "Open pkg_database at \"%s\".", location);
#endif

        if ((r = db->vtable->open(db, location, f)) == PKG_OK) {
		db->status = OPEN;
	}
        /* Need the return value incase we caught a fatal. */
        return (r);
}

int
pkg_database_close(struct pkg_database *db)
{
        int r;

        if (db->status != OPEN) {
                return (PKG_NOT_OK);
        }
        if ((r = db->vtable->close(db)) == PKG_OK) {
                db->status = CLOSED;
        }
        return (r);
}

/* Get the next package in a database. */
int
pkg_database_get_next_pkg(struct pkg_database *db, struct pkg *p, u_int f) 
{
        int r;

        _pkg_check_magic(p, __func__);
        _pkg_database_check_magic(db, __func__);
        
        if (db->status != OPEN) {
                return (PKG_NOT_OK);
        }

        /* 
         * The database and package have both been validated.  Clear the package
         * and pass it to the _get_next_pkg function in the vtable.
         */
        pkg_clear(p);
        r = db->vtable->get_next_pkg(db, p, f);
        if (r == PKG_FATAL) {
                PKG_CLIENT_CRASH(__func__, "Got PKG_FATAL");
        }

        return (r);
}

#if 0
int
pkg_database_get_pkg(struct pkg_database *db, struct pkg *, u_int f)
{
        int r;

        _pkg_check_magic(p, __func__);
        _pkg_database_check_magic(db, __func__);

        if (db->status != OPEN) {
                PKG_CLIENT_CRASH(__func__, "Database is not open");
        }

        r = db->vtable->get_pkg(db, p, f);
        
        PKG_CLIENT_CRASH(__func__, "Not implemented.");
        
        return (r)
}
#endif

void
pkg_database_rewind(struct pkg_database *db)
{
        _pkg_database_check_magic(db, __func__);
        db->vtable->rewind(db);
}

int
pkg_database_add_pkg(struct pkg_database *db, struct pkg *p, u_int f)
{
#if 0
        int r;
#endif
        (void)f;

        _pkg_check_magic(p, __func__);

        if (db->status != OPEN) {
                /* Just leave. */
                return (PKG_NOT_OK);
        }
        /* Log this action. */
        /* 
         * This functions will put weird shit in your logs if you haven't set
         * the key_name attribute.
         */
#if 0
        r = pkg_logging_log_database_add(p, db->vtable->add, db, p, f);
        return (r);
#endif
        PKG_CLIENT_CRASH(__func__, "Not implemented.");
        return (PKG_NOT_OK);
}

int
pkg_database_remove_pkg(struct pkg_database *db, const char *name)
{
        _pkg_database_check_magic(db, __func__);

        return (db->vtable->remove_pkg(db, name));
}
